﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Collections.Specialized;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
namespace PTA.Net
{
    /// <summary>
    /// WEB客户端工具类
    /// </summary>
    public class WebClient
    {
        #region 创建一个HTTP请求
        /// <summary>
        /// 创建一个HTTP请求
        /// </summary>
        /// <returns>FTP请求</returns>
        private static HttpWebRequest CreateWebRequest(WebRequestInfo wri)
        {
            //建立连接
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(wri.Url);
            if (wri.Proxy != null)
            {
                request.Proxy = wri.Proxy;
            }
            request.KeepAlive = false;//命令执行完毕之后关闭连接
            if (wri.Method != HttpMethod.None)
            {
                switch (wri.Method)
                {
                    case HttpMethod.Get:
                        {
                            request.Method = WebRequestMethods.Http.Get;
                            break;
                        }
                    case HttpMethod.Head:
                        {
                            request.Method = WebRequestMethods.Http.Head;
                            break;
                        }
                    case HttpMethod.Post:
                        {
                            request.Method = WebRequestMethods.Http.Post;
                            break;
                        }
                    case HttpMethod.Put:
                        {
                            request.Method = WebRequestMethods.Http.Put;
                            break;
                        }
                    case HttpMethod.Connect:
                        {
                            request.Method = WebRequestMethods.Http.Connect;
                            break;
                        }
                }
            }
            request.Timeout = wri.Timeout * 1000;
            request.KeepAlive = wri.KeepAlive;
            if (wri.Headers != null && wri.Headers.Count > 0)
            {
                if (request.Headers == null)
                {
                    request.Headers = new WebHeaderCollection();
                }
                for (int i = 0; i < wri.Headers.Count; i++)
                {
                    request.Headers.Add(wri.Headers.GetKey(i), wri.Headers[i]);
                }
            }
            if (!string.IsNullOrEmpty(wri.ContentType))
            {
                request.ContentType = wri.ContentType;
            }
            if (wri.ContentLength > 0)
            {
                request.ContentLength = wri.ContentLength;
            }
            if (!string.IsNullOrEmpty(wri.Accept))
            {
                request.Accept = wri.ContentType;
            }
            if (!string.IsNullOrEmpty(wri.Expect))
            {
                request.Expect = wri.ContentType;
            }
            if (!string.IsNullOrEmpty(wri.Referer))
            {
                request.Referer = wri.ContentType;
            }

            if (wri.Cookies != null && wri.Cookies.Count > 0)
            {
                request.CookieContainer = wri.Cookies;
            }
            if (!string.IsNullOrEmpty(wri.UserAgent))
            {
                request.UserAgent = wri.UserAgent;
            }
            return request;
        }
        #endregion

        #region 创建SOAP请求

        /// <summary>
        /// 发送Soap请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="action">动作</param>
        /// <param name="content">数据</param>
        /// <returns>请求结果</returns>
        public static string SendSoap(string url, string action, string content)
        {
            WebRequestInfo wri = new WebRequestInfo();
            wri.Url = url;
            return SendSoap(wri, action, content);
        }

        /// <summary>
        /// 发送Soap请求
        /// </summary>
        /// <param name="wri">请求的详细信息</param>
        /// <param name="action">动作</param>
        /// <param name="content">数据</param>
        /// <returns>请求结果</returns>
        public static string SendSoap(WebRequestInfo wri, string action, string content)
        {
            wri.Method = HttpMethod.Post;
            HttpWebRequest request = CreateWebRequest(wri);
            if (content.EndsWith(@"</soap12:Envelope>"))
            {
                request.ContentType = "application/soap+xml; charset=utf-8";
            }
            else
            {
                request.Headers.Add("SOAPAction", action);
                request.ContentType = "text/xml; charset=utf-8";
            }
            byte[] bytes = Encoding.UTF8.GetBytes(content);
            request.ContentLength = bytes.Length;
            try
            {
                request.GetRequestStream().Write(bytes, 0, bytes.Length);
            }
            finally
            {
                request.GetRequestStream().Close();
            }
            StreamReader sr = new StreamReader(request.GetResponse().GetResponseStream());
            string result = sr.ReadToEnd();
            sr.Close();
            request.GetResponse().GetResponseStream().Close();
            return result;
        }

        #endregion

        #region 创建HTTP请求

        /// <summary>
        /// 发送Http请求
        /// </summary>
        /// <param name="url">请求的地址</param>
        /// <param name="result">返回结果</param>
        public static void SendHttp(string url, Stream result)
        {
            WebRequestInfo wri = new WebRequestInfo();
            wri.Url = url;
            SendHttp(wri, null, result);
        }

        /// <summary>
        /// 发送Http请求
        /// </summary>
        /// <param name="wri">请求的详细信息</param>
        /// <param name="result">返回结果</param>
        public static void SendHttp(WebRequestInfo wri, Stream result)
        {
            SendHttp(wri, null, result);
        }

        /// <summary>
        /// 发送Http请求
        /// </summary>
        /// <param name="url">请求的地址</param>
        /// <param name="content">请求发送的数据</param>
        /// <param name="result">返回结果</param>
        public static void SendHttp(string url, Stream content, Stream result)
        {
            WebRequestInfo wri = new WebRequestInfo();
            wri.Url = url;
            SendHttp(wri, content, result);
        }

        /// <summary>
        /// 发送Http请求
        /// </summary>
        /// <param name="wri">请求的详细信息</param>
        /// <param name="content">请求发送的数据</param>
        /// <param name="result">返回结果</param>
        public static void SendHttp(WebRequestInfo wri, Stream content, Stream result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }
            if (!result.CanWrite)
            {
                throw new ArgumentException("result流必须是可写的");
            }
            HttpWebRequest request = CreateWebRequest(wri);
            byte[] buffer = new byte[5120];
            int length;
            if (wri.Method == HttpMethod.Post)
            {
                if (content != null && content.CanRead)
                {
                    try
                    {
                        length = content.Read(buffer, 0, buffer.Length);
                        while (length > 0)
                        {
                            request.GetRequestStream().Write(buffer, 0, length);
                            length = content.Read(buffer, 0, buffer.Length);
                        }
                    }
                    finally
                    {
                        request.GetRequestStream().Close();
                    }
                }
                else
                {
                    request.ContentLength = 0;
                }
            }
            else
            {
                request.ContentLength = 0;
            }
            long posion = result.Seek(0, SeekOrigin.Begin);
            length = request.GetResponse().GetResponseStream().Read(buffer, 0, buffer.Length);
            while (length > 0)
            {
                result.Write(buffer, 0, length);
                length = request.GetResponse().GetResponseStream().Read(buffer, 0, buffer.Length);
            }
            result.Seek(posion, SeekOrigin.Begin);
        }

        #endregion

        #region 创建HTTPS请求

        /// <summary>
        /// 发送Https请求(注意设置:ServicePointManager.ServerCertificateValidationCallback)
        /// </summary>
        /// <param name="url">请求的地址</param>
        /// <param name="certs">证书信息</param>
        /// <param name="result">返回结果</param>
        public static void SendHttps(string url, Stream result, params X509Certificate[] certs)
        {
            WebRequestInfo wri = new WebRequestInfo();
            wri.Url = url;
            SendHttps(wri, null, result, certs);
        }

        /// <summary>
        /// 发送Https请求(注意设置:ServicePointManager.ServerCertificateValidationCallback)
        /// </summary>
        /// <param name="wri">请求的详细信息</param>
        /// <param name="certs">证书信息</param>
        /// <param name="result">返回结果</param>
        public static void SendHttps(WebRequestInfo wri, Stream result, params X509Certificate[] certs)
        {
            SendHttps(wri, null, result, certs);
        }

        /// <summary>
        /// 发送Https请求(注意设置:ServicePointManager.ServerCertificateValidationCallback)
        /// </summary>
        /// <param name="url">请求的地址</param>
        /// <param name="certs">证书信息</param>
        /// <param name="content">请求发送的数据</param>
        /// <param name="result">返回结果</param>
        public static void SendHttps(string url, Stream content, Stream result, params X509Certificate[] certs)
        {
            WebRequestInfo wri = new WebRequestInfo();
            wri.Url = url;
            SendHttps(wri, content, result, certs);
        }

        /// <summary>
        /// 发送Https请求(注意设置:ServicePointManager.ServerCertificateValidationCallback)
        /// </summary>
        /// <param name="wri">请求的详细信息</param>
        /// <param name="certs">证书信息</param>
        /// <param name="content">请求发送的数据</param>
        /// <param name="result">返回结果</param>
        public static void SendHttps(WebRequestInfo wri, Stream content, Stream result, params X509Certificate[] certs)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }
            if (!result.CanWrite)
            {
                throw new ArgumentException("result流必须是可写的");
            }
            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
            HttpWebRequest request = CreateWebRequest(wri);
            request.ClientCertificates.Clear();
            foreach (X509Certificate cert in certs)
            {
                request.ClientCertificates.Add(cert);
            }
            byte[] buffer = new byte[5120];
            int length;
            if (wri.Method == HttpMethod.Post)
            {
                if (content != null && content.CanRead)
                {
                    try
                    {
                        length = content.Read(buffer, 0, buffer.Length);
                        while (length > 0)
                        {
                            request.GetRequestStream().Write(buffer, 0, length);
                            length = content.Read(buffer, 0, buffer.Length);
                        }
                    }
                    finally
                    {
                        request.GetRequestStream().Close();
                    }
                }
                else
                {
                    request.ContentLength = 0;
                }
            }
            else
            {
                request.ContentLength = 0;
            }
            long position = result.Seek(0, SeekOrigin.Begin);
            length = request.GetResponse().GetResponseStream().Read(buffer, 0, buffer.Length);
            while (length > 0)
            {
                result.Write(buffer, 0, length);
                length = request.GetResponse().GetResponseStream().Read(buffer, 0, buffer.Length);
            }
            result.Seek(position, SeekOrigin.Begin);
        }

        #endregion

        internal static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            //直接确认，否则打不开
            return true;
        }
    }

    /// <summary>
    /// WEB请求的描述信息
    /// </summary>
    public class WebRequestInfo
    {
        #region 主机
        private string url = string.Empty;
        /// <summary>
        /// 主机
        /// </summary>
        public string Url
        {
            get
            {
                return this.url;
            }
            set
            {
                this.url = value;
            }
        }
        #endregion

        #region 代理
        IWebProxy proxy = WebProxy.GetDefaultProxy();
        /// <summary>
        /// 代理
        /// </summary>
        public IWebProxy Proxy
        {
            get
            {
                return this.proxy;
            }
            set
            {
                this.proxy = value;
            }
        }
        #endregion

        #region 方法
        private HttpMethod method = HttpMethod.Post;
        /// <summary>
        /// 获取或设置HttpRequest使用的方法(默认:Post)
        /// </summary>
        public HttpMethod Method
        {
            get
            {
                return this.method;
            }
            set
            {
                this.method = value;
            }
        }
        #endregion

        #region 获取或设置与此请求关联的cookie。
        private CookieContainer cookies = null;
        /// <summary>
        /// 获取或设置与此请求关联的cookie.
        /// </summary>
        public CookieContainer Cookies
        {
            get
            {
                if (this.cookies == null)
                {
                    this.cookies = new CookieContainer();
                }
                return this.cookies;
            }
        }
        #endregion

        #region 获取或设置请求的超时值。
        private int timeout = 180;
        /// <summary>
        /// 获取或设置请求的超时值,默认180秒。
        /// </summary>
        public int Timeout
        {
            get
            {
                return this.timeout;
            }
            set
            {
                this.timeout = value > 0 ? value : 30;
            }
        }
        #endregion

        #region 获取或设置 User-agent HTTP 标头的值
        private string userAgent = string.Empty;
        /// <summary>
        /// 获取或设置 User-agent HTTP 标头的值
        /// </summary>
        public string UserAgent
        {
            get
            {
                return this.userAgent;
            }
            set
            {
                this.userAgent = value;
            }
        }
        #endregion

        #region 要提交的内容的类型
        private string contentType;
        /// <summary>
        /// 要提交的内容的类型(默认:text/xml;charset=UTF-8)
        /// </summary>
        public string ContentType
        {
            get
            {
                return this.contentType;
            }
            set
            {
                this.contentType = value;
            }
        }
        #endregion

        #region HttpHeader信息
        private WebHeaderCollection headers = null;
        /// <summary>
        /// 获取或设置Http请求头
        /// </summary>
        public WebHeaderCollection Headers
        {
            get
            {
                return this.headers;
            }
            set
            {
                this.headers = value;
            }
        }


        public long ContentLength { get; set; }
        public string Accept { get; set; }
        public string Expect { get; set; }
        public string Referer { get; set; }
        public bool KeepAlive { get; set; }

        #endregion
    }

    /// <summary>
    /// WEB客户端常用方法
    /// </summary>
    public enum HttpMethod
    {
        /// <summary>
        /// 不指定方法
        /// </summary>
        None,

        /// <summary>
        /// http get 方法
        /// </summary>
        Get,

        /// <summary>
        /// http head 方法
        /// </summary>
        Head,

        /// <summary>
        /// http post 方法
        /// </summary>
        Post,

        /// <summary>
        /// http connect 方法
        /// </summary>
        Connect,

        /// <summary>
        /// http put 方法
        /// </summary>
        Put
    }
}
